package service

import (
	"context"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"prod/api/prod"
	"prod/internal/constant"
	"prod/internal/model"
	"prod/pkg/ecode"
	"time"
)

func (s *Service) GetProdTypeList(ctx context.Context, req *prod.GetProdTypeListRequest) (
	resp *prod.GetProdTypeListResponse, err error) {
	if err = s.dao.CheckPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var rawList []*model.ProdTypeQueryModel
	if rawList, err = s.dao.LoadProdTypeListWithCount(ctx, req.Token.SgId, req.PStoreId, req.Nature); err != nil {
		return
	}
	prodTypeDict := make(map[uint32]*prod.ProdTypeView)
	for _, prodType := range rawList {
		if prodType.ParentId != 0 {
			prodTypeDict[prodType.ParentId].Subs = append(prodTypeDict[prodType.ParentId].Subs, &prod.ProdTypeView{
				Id:    prodType.ID,
				Name:  prodType.Name,
				Count: prodType.Count,
			})
			prodTypeDict[prodType.ParentId].Count += prodType.Count
		} else {
			prodTypeDict[prodType.ID] = &prod.ProdTypeView{
				Id:   prodType.ID,
				Name: prodType.Name,
				Subs: make([]*prod.ProdTypeView, 0),
			}
		}
	}
	resp = &prod.GetProdTypeListResponse{ProdTypes: make([]*prod.ProdTypeView, 0)}
	for _, prodType := range rawList {
		if val, ok := prodTypeDict[prodType.ID]; ok {
			resp.ProdTypes = append(resp.ProdTypes, val)
		}
	}
	return
}

func (s *Service) CreateProdType(ctx context.Context, req *prod.CreateProdTypeRequest) (
	resp *prod.CommonObjectResponse, err error) {
	if err = s.dao.CheckPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	resp = &prod.CommonObjectResponse{}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var existType *model.ProdType
		if req.ParentId != 0 {
			// 检查菜类存在
			var parentType *model.ProdType
			if parentType, err = s.dao.GetProdTypeByID(ctx, req.ParentId, req.Token.SgId, req.PStoreId); err != nil {
				if errors.Cause(err) == gorm.ErrRecordNotFound {
					err = constant.ErrObjectNotExist
				}
				return
			} else if prod.Nature(parentType.Nature) != req.Nature {
				err = ecode.BadRequest("父类目类型与创建类型不匹配")
				return
			} else if parentType.ParentId != 0 {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "暂时不支持三级类目")
				return
			}
		}
		if existType, err = s.dao.GetProdTypeByName(
			ctx, req.Name, req.Token.SgId, req.PStoreId, req.ParentId); err == nil {
			if existType.Status {
				err = constant.ErrDuplicateInput
				return
			} else {
				// 延续同名ID, 确保统计意义连续
				now := time.Now()
				existType.Status = true
				existType.Nature = uint8(req.Nature)
				existType.Operator = req.Token.EmpId
				existType.CreatedAt = now
				existType.UpdatedAt = now
				if err = s.dao.Save(ctx, existType); err != nil {
					return
				}
				resp.Id = existType.ID
			}
		} else if errors.Cause(err) != gorm.ErrRecordNotFound {
			return
		} else {
			prodType := &model.ProdType{
				Name:     req.Name,
				SgId:     req.Token.SgId,
				PStoreId: req.PStoreId,
				Nature:   uint8(req.Nature),
				ParentId: req.ParentId,
				Operator: req.Token.EmpId,
				Status:   true,
			}
			if err = s.dao.Create(ctx, prodType); err != nil {
				return
			}
			resp.Id = prodType.ID
		}

		return
	}); err != nil {
		return
	}
	return
}

func (s *Service) EditProdType(ctx context.Context, req *prod.EditProdTypeRequest) (resp *prod.DefaultResp, err error) {
	if err = s.dao.CheckPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var dupNameType *model.ProdType
		// 锁定正确状态的记录
		existType := &model.ProdType{}
		if err = s.dao.LockObjectByID(ctx, existType, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
			}
			return
		}
		if req.ParentId != 0 {
			// 检查菜类存在
			var parentType *model.ProdType
			if parentType, err = s.dao.GetProdTypeByID(ctx, req.ParentId, req.Token.SgId, req.PStoreId); err != nil {
				if errors.Cause(err) == gorm.ErrRecordNotFound {
					err = constant.ErrObjectNotExist
				}
				return
			} else if parentType.ParentId != 0 {
				// 暂时不支持超过二级类目
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "暂时不支持三级类目")
				return
			}
		} else if existType.ParentId != 0 {
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "不允许将一级类目改为二级类目")
			return
		}
		// 只允许修改名称&父类别
		if existType.Name != req.Name || existType.ParentId != req.ParentId {
			if dupNameType, err = s.dao.GetProdTypeByName(
				ctx, req.Name, req.Token.SgId, req.PStoreId, req.ParentId); err == nil {
				if dupNameType.Status && dupNameType.ID != req.Id {
					// 与有效数据重名
					err = constant.ErrDuplicateInput
					return
				} else if !dupNameType.Status {
					// 与已删除同名，关联置换
					now := time.Now()
					dupNameType.Status = true
					dupNameType.Nature = existType.Nature
					dupNameType.Operator = req.Token.EmpId
					dupNameType.CreatedAt = now
					dupNameType.UpdatedAt = now
					if err = s.dao.Save(ctx, dupNameType); err != nil {
						return
					}
					existType.Status = false
					existType.Operator = req.Token.EmpId
					if err = s.dao.Save(ctx, existType); err != nil {
						return
					}
					if err = s.dao.ReplaceProdType(ctx, existType.ID, dupNameType.ID, req.Token.EmpId); err != nil {
						return
					}
				} else {
					return
				}
			} else {
				// 无重名
				existType.Name = req.Name
				existType.ParentId = req.ParentId
				existType.Operator = req.Token.EmpId
				if err = s.dao.Save(ctx, existType); err != nil {
					return
				}
			}
		}
		return
	}); err != nil {
		return
	}
	return
}

func (s *Service) DeleteProdType(ctx context.Context, req *prod.CommonObjectRequest) (resp *prod.DefaultResp, err error) {
	if err = s.dao.CheckPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	resp = &prod.DefaultResp{Status: true}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		// 锁定正确状态的记录
		existType := &model.ProdType{}
		if err = s.dao.LockObjectByID(ctx, existType, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
			}
			return
		}
		if existType.ParentId == 0 {
			// 删除一级类目，检查有无关联的二级类目
			var subTypes []*model.ProdType
			if subTypes, err = s.dao.GetSubTypes(ctx, req.Token.SgId, req.PStoreId, req.Id); err != nil {
				return
			}
			if len(subTypes) != 0 {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "请先删除二级类别，再删除父类别")
				return
			}
		} else {
			var prodCount int64
			if prodCount, err = s.dao.GetProdCountByTypeId(ctx, req.Token.SgId, req.PStoreId, req.Id); err != nil {
				return
			}
			if prodCount != 0 {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "商品类别仍在有商品在使用, 不能删除")
				return
			}
		}
		existType.Status = false
		existType.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, existType); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	return
}

func (s *Service) getProdTypeMapByIds(ctx context.Context, typeIds []uint32, sgId, pStoreId uint32) (
	prodTypeMap map[uint32]string, err error) {
	var prodTypes []*prod.SimpleProdTypeView
	if prodTypes, err = s.dao.GetSimpleProdTypeByIDs(ctx, typeIds, sgId, pStoreId); err != nil {
		return
	}
	prodTypeMap = make(map[uint32]string)
	for _, prodType := range prodTypes {
		prodTypeMap[prodType.Id] = prodType.Name
	}
	return
}
